﻿#!/usr/bin/env python
# -*- coding: utf-8 -*-

# structure.py

# Copyright 2009-2010 Diego Hansen Hahn (aka DiegoHH) <diegohh90 [at] hotmail [dot] com>

# lazynds is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.

# lazynds is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with lazynds. If not, see <http://www.gnu.org/licenses/>.

import struct
import timedebugger

nintendo_logo = "\
\x24\xff\xae\x51\x69\x9a\xa2\x21\x3d\x84\x82\x0a\x84\xe4\x09\xad\
\x11\x24\x8b\x98\xc0\x81\x7f\x21\xa3\x52\xbe\x19\x93\x09\xce\x20\
\x10\x46\x4a\x4a\xf8\x27\x31\xec\x58\xc7\xe8\x33\x82\xe3\xce\xbf\
\x85\xf4\xdf\x94\xce\x4b\x09\xc1\x94\x56\x8a\xc0\x13\x72\xa7\xfc\
\x9f\x84\x4d\x73\xa3\xca\x9a\x61\x58\x97\xa3\x27\xfc\x03\x98\x76\
\x23\x1d\xc7\x61\x03\x04\xae\x56\xbf\x38\x84\x00\x40\xa7\x0e\xfd\
\xff\x52\xfe\x03\x6f\x95\x30\xf1\x97\xfb\xc0\x85\x60\xd6\x80\x25\
\xa9\x63\xbe\x03\x01\x4e\x38\xe2\xf9\xa2\x34\xff\xbb\x3e\x03\x44\
\x78\x00\x90\xcb\x88\x11\x3a\x94\x65\xc0\x7c\x63\x87\xf0\x3c\xaf\
\xd6\x25\xe4\x8b\x38\x0a\xac\x72\x21\xd4\xf8\x07"

def Crc16(string):
    polynomial = 0xA001

    table = array.array('H')
    #Gera￧ção dos polin￴ômios
    for byte in range(256):
        crc = 0
        for bit in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ polynomial
            else:
                crc >>= 1
            byte >>= 1
        table.append(crc)

    #Cálculo do CHECKSUM
    crc = 0xffff
    for x in string:
        crc = (crc >> 8) ^ table[(crc ^ ord(x)) & 0xff]

    return crc

def isNds(fd):
    fd.seek(0xc0, 0)
    rom_logo = fd.read(156)
    # Compara o logo da Nintendo com o original. Se diferente, retorna Falso
    if rom_logo != nintendo_logo:
        return False
    # Verifica o checksum do logo.. deve ser cf56h
    checksum = struct.unpack('<H', fd.read(2))[0]
    if checksum != 0xcf56:
        return False
    return True

def isGba(fd):
    fd.seek(0x04, 0)
    rom_logo = fd.read(156)
    # Compara o logo da Nintendo com o original. Se diferente, retorna Falso
    if rom_logo != nintendo_logo:
        return False
    fd.seek(0xb2, 0)
    #Verifica o valor fixo... dever ser 96h
    fixed_value = struct.unpack('B', fd.read(1))[0]
    if fixed_value != 0x96:
        return False
    return True

def getGbaPointer(fd, offset):
    if offset >= 0x2000000:
        return ValueError('offset greater than 0x2000000.')
    results = []
    offset |= 0x8000000
    fd.seek(0,0)
    file_map = fd.read()
    i = 0
    while i < len(file_map):
        pointer = struct.unpack('<L', file_map[i:(i+4)])[0]
        if pointer == offset:
            results.append(i)
        i += 4

    return results

def readNdsFat(fd):

    fat = [[],[]]

    fd.seek(0x48, 0)
    fat_address = struct.unpack('<L', fd.read(4))[0]
    fat_size = struct.unpack('<L', fd.read(4))[0]

    fd.seek(fat_address, 0)
    entries = fat_size / 8
    for x in range(entries):
        f_start = struct.unpack('<L', fd.read(4))[0]
        f_end = struct.unpack('<L', fd.read(4))[0]
        fat[0].append(f_start)
        fat[1].append(f_end)

    return fat

def getNdsFatEntry(fd, address, fat):
    if address not in fat[0]:
        return False

    index = fat[0].index(address)
    fd.seek(0x48, 0)
    fat_address = struct.unpack('<L', fd.read(4))[0]

    return (fat_address + index * 16)

def getHeight(size, width):
    if size % width == 0:
        height = size / width
    else:
        height = (size / width) + 1

    if height % 8 != 0:
        height += 8 - (height % 8)

    return height
